package com.bphx.android.activities;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import com.bphx.android.IStorage;
import com.bphx.android.R;
import com.bphx.android.activities.adapters.VariantsListAdapter;
import com.bphx.android.db.IOptionsHolder;
import com.bphx.android.db.Storage;
import com.bphx.android.exception.BaseException;
import com.bphx.android.ui.ISpeecher;
import com.bphx.android.ui.listeners.IAnswersListener;
import com.bphx.android.utils.SpeecherStatus;
import com.bphx.android.words.Word;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Random;

import static android.speech.tts.TextToSpeech.Engine.CHECK_VOICE_DATA_PASS;
import static android.speech.tts.TextToSpeech.SUCCESS;
import static android.widget.Toast.LENGTH_SHORT;
import static android.widget.Toast.makeText;
import static com.bphx.android.R.id.*;
import static com.bphx.android.R.layout.training;
import static com.bphx.android.R.string.*;
import static com.bphx.android.utils.Constants.*;
import static com.bphx.android.utils.SpeecherStatus.*;
import static com.bphx.android.utils.Utils.createVariantsString;
import static com.bphx.android.utils.Utils.isMoreThen;
import static java.lang.Integer.MAX_VALUE;
import static java.lang.Integer.valueOf;
import static java.lang.Math.floor;
import static java.util.Collections.EMPTY_LIST;
import static java.util.Collections.shuffle;
import static org.apache.commons.lang.StringUtils.isBlank;

/**
 * @author Vyacheslav Kovalyov
 * @version 1.0
 */
public class TrainingActivity extends Activity implements IAnswersListener, ISpeecher {

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(training);

        findViewById(training_stop).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });

        initWidgets();
        random = new Random();
        speecherStatus = INIT_ERROR;

        Intent checkTTSIntent = new Intent();
        checkTTSIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
        startActivityForResult(checkTTSIntent, TTS_CHECK_CODE);

        if (savedInstanceState == null) {
            initWordsCount();
            initWords();
            populateStatistic();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == TTS_CHECK_CODE) {
            if (resultCode == CHECK_VOICE_DATA_PASS) {
                speecher = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
                    @Override
                    public void onInit(int status) {
                        if (status == SUCCESS) {

                            IOptionsHolder holder = new Storage(TrainingActivity.this);
                            Locale locale = new Locale(holder.getOption(SPEAKER_LOCALE));
                            int langStatus = speecher.setLanguage(locale);

                            if (langStatus == SUCCESS) {
                                speecherStatus = STATUS_SUCCESS;
                            } else {
                                speecherStatus = UNSUPPORTED_LOCALE;
                            }
                        } else {

                            installDialog = new InstallDialog(TrainingActivity.this);
                            installDialog.show();
                        }
                    }
                });
            }
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    protected void onRestoreInstanceState(Bundle savedInstanceState) {

        super.onRestoreInstanceState(savedInstanceState);

        words = savedInstanceState.getParcelableArrayList(WORDS);
        currentWord = savedInstanceState.getParcelable(CURRENT_WORD);
        statistic = (HashMap<String, Integer>) savedInstanceState.getSerializable(STATISTIC);
        wrongAnswer = savedInstanceState.getBoolean(WRONG_ANSWER);

        ArrayList<String> variants = savedInstanceState.getStringArrayList(VARIANTS);

        if (words == null || currentWord == null) {
            initWords();
            return;
        }

        if (!wordsIsCorrect()) {
            return;
        }

        initForm(currentWord, variants);
        populateStatistic();
        checkIsFinish();
    }

    @Override
    protected void onDestroy() {
        if (finishDlg != null && finishDlg.isShowing()) {
            finishDlg.cancel();
        }

        if (installDialog != null && installDialog.isShowing()) {
            installDialog.cancel();
        }

        speecher.shutdown();
        super.onDestroy();
    }

    @Override
    @SuppressWarnings("unchecked")
    protected void onSaveInstanceState(Bundle outState) {

        outState.putParcelableArrayList(WORDS, words);
        outState.putParcelable(CURRENT_WORD, currentWord);
        outState.putSerializable(STATISTIC, statistic);
        outState.putBoolean(WRONG_ANSWER, wrongAnswer);

        if (actualVariants == null) {
            actualVariants = (ArrayList) EMPTY_LIST;
        }
        outState.putStringArrayList(VARIANTS, actualVariants);

        super.onSaveInstanceState(outState);
    }

    @Override
    public void dispatchWrongAnswer() {
        wrongAnswer = true;
        makeText(this, textInvalidAnsever, LENGTH_SHORT).show();
    }

    @Override
    public void dispatchRightAnswer() {

        initForm(getRandomWord());

        int rightAnswers = statistic.get(RIGHT_ANSWERS);
        if (!wrongAnswer) {
            statistic.put(RIGHT_ANSWERS, rightAnswers + 1);
        }

        wrongAnswer = false;
        statistic.put(TOTAL_ANSWERS, statistic.get(TOTAL_ANSWERS) + 1);
        populateStatistic();
        checkIsFinish();
    }

    @Override
    public void speech(String text) {
        String textForSpeak = text.trim();

        switch (speecherStatus) {
            case STATUS_SUCCESS:
                if (speecher.isSpeaking()) {
                    speecher.stop();
                }
                speecher.speak(textForSpeak, TextToSpeech.QUEUE_FLUSH, null);
                break;
            case INIT_ERROR:
                makeText(this, getString(textSpeecherCanBotSay, getString(textSpeecherInitError)), LENGTH_SHORT).show();
                return;
            case UNSUPPORTED_LOCALE:
                makeText(this, getString(textSpeecherCanBotSay, getString(textUnsupportedLocale)), LENGTH_SHORT).show();
        }
    }

    private void checkIsFinish() {
        if (statistic.get(TOTAL_ANSWERS) >= statistic.get(COUNT)) {
            finishDlg = new FinishDialog(this, statistic);
            finishDlg.show();
        }
    }

    private void removeWord(Word word) {
        if (word == null) {
            return;
        }

        words.remove(word);
        if (words.isEmpty()) {
            initWords();
        }
    }

    private void populateStatistic() {
        TextView tw = (TextView) findViewById(R.id.statistic);
        tw.setText(getString(textStatistic, statistic.get(RIGHT_ANSWERS),
                statistic.get(TOTAL_ANSWERS), calculatePercentage()));
    }

    private int calculatePercentage() {

        if (statistic.get(TOTAL_ANSWERS) <= 0 || statistic.get(RIGHT_ANSWERS) <= 0) {
            return 0;
        }

        return (int) floor((statistic.get(RIGHT_ANSWERS) * 100) / statistic.get(TOTAL_ANSWERS));
    }

    private boolean wordsIsCorrect() {
        if (words.size() == 0) {
            originalWord.setText(textErrorNoWords);
            return false;
        }

        return true;
    }

    private void initWords() {
        IStorage storage = new Storage(this);

        try {
            words = storage.loadWords();
        } catch (BaseException e) {
            originalWord.setText(unableLoadData);
            return;
        }

        if (!wordsIsCorrect()) {
            return;
        }

        initForm(getRandomWord());
    }

    private void initWidgets() {

        originalWord = (TextView) findViewById(R.id.originalWord);
        listView = (ListView) findViewById(training_list);
        helpButton = (Button) findViewById(training_help);
    }

    private Word getRandomWord() {

        Word newWord;
        removeWord(currentWord);

        int attempts = 0;

        do {
            newWord = words.get(random.nextInt(words.size()));
            attempts++;
        } while ((newWord.equals(currentWord) || attempts < MAX_ATTEMPTS) && words.size() > 1);

        return newWord;
    }

    private void initForm(final Word word, ArrayList<String> variants) {
        currentWord = word;

        originalWord.setText(word.getOriginalWord());
        helpButton.setOnClickListener(new HelpButtonClickListener(word));

        if (variants == null) {
            int variantNumber = random.nextInt(word.getVariants().size());

            variants = new ArrayList<String>();
            variants.add(word.getVariants().get(variantNumber));
            variants.addAll(word.getInvalidTranslations());

            shuffle(variants);
        }

        if (variants.isEmpty()) {
            if (words.size() > 1) {
                initForm(getRandomWord());
            }

            return;
        }

        listView.setAdapter(new VariantsListAdapter(this, currentWord, variants));
        actualVariants = variants;
    }

    private void initForm(final Word word) {
        initForm(word, null);
    }

    private class HelpButtonClickListener implements View.OnClickListener {

        private HelpButtonClickListener(Word word) {
            this.word = word;
        }

        @Override
        public void onClick(View v) {
            String message = createVariantsString(word.getVariants());
            AlertDialog alert = new DialogBuilder(message).create();
            alert.show();
        }

        private Word word;
    }

    private class DialogBuilder extends AlertDialog.Builder {

        public DialogBuilder(String message) {
            super(TrainingActivity.this);

            setMessage(message);
            setCancelable(false);
            setPositiveButton(R.string.textOk, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    dialog.cancel();
                }
            });
        }
    }

    private void initWordsCount() {

        statistic = new HashMap<String, Integer>();
        statistic.put(RIGHT_ANSWERS, 0);
        statistic.put(TOTAL_ANSWERS, 0);

        IOptionsHolder holder = new Storage(this);
        String wordsCountStr = holder.getOption(OPTION_WORDS_COUNT).trim();

        if (isBlank(wordsCountStr) || !isMoreThen(0, wordsCountStr)) {
            statistic.put(COUNT, MAX_VALUE);
        } else {
            statistic.put(COUNT, valueOf(wordsCountStr));
        }
    }

    private class FinishDialog extends AlertDialog {

        protected FinishDialog(Context context, HashMap<String, Integer> statistic) {
            super(context);

            setTitle(textTrainingFinished);
            setMessage(getString(textStatistic, statistic.get(RIGHT_ANSWERS),
                    statistic.get(TOTAL_ANSWERS), calculatePercentage()));

            setButton(BUTTON_POSITIVE, getString(textFinish), new OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    cancel();
                    finish();
                }
            });
        }
    }

    private class InstallDialog extends AlertDialog {

        protected InstallDialog(Context context) {
            super(context);

            setTitle(textInstallService);
            setMessage(getString(textInstallTTS));

            setButton(BUTTON_POSITIVE, getString(textOk), new OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    Intent installTTSIntent = new Intent();
                    installTTSIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
                    cancel();
                    startActivity(installTTSIntent);
                }
            });

            setButton(BUTTON_NEGATIVE, getString(textCancel), new OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    cancel();
                }
            });
        }
    }

    private Dialog installDialog;
    private TextToSpeech speecher;
    private SpeecherStatus speecherStatus;

    private HashMap<String, Integer> statistic;
    private ArrayList<Word> words;
    private boolean wrongAnswer = false;

    private Random random;
    private TextView originalWord;
    private ListView listView;

    private Button helpButton;
    private Dialog finishDlg;

    //use only for saving state
    private Word currentWord;
    private ArrayList<String> actualVariants;

    //statistic keys
    private static final String COUNT = "COUNT";
    private static final String RIGHT_ANSWERS = "RIGHT_ANSWERS ";
    private static final String TOTAL_ANSWERS = "TOTAL_ANSWERS";
    private static final int MAX_ATTEMPTS = 10;
    private static final int TTS_CHECK_CODE = 100500;
}